#include <kutils.h>
#include "mouse.h"
#include "irq.h"
#include "display.h"

s32int mouse_wait_write(void);
s32int mouse_wait_read(void);
s32int mouse_send_command(u8int command);
s32int mouse_get_data(u8int* data);
void mouse_handler(struct regs *r);

u8int packet_size = 3;
u32int pos_x = 0;
u32int pos_y = 0;
u8int mouse_packet[3];
u8int mouse_packet_index = 0;

s32int mouse_wait_write(void)
{
	u32int timeout = MOUSE_TIMEOUT;
	//wait for bit 1 of port 0x64 to clear
	while(timeout) 
	{
		if(!(inportb(0x64) & 0x02))
			return 1;

		wait(10);
		timeout--;
	}
	write_string("Mouse: Write Timeout\n");
	return 0;
}

s32int mouse_wait_read(void)
{
	u32int timeout = MOUSE_TIMEOUT;

	//wait for bit 0 of port 0x64 to be set
	while(timeout) 
	{
		if(inportb(0x64) & 0x01)
			return 1;

		wait(10);
		timeout--;
	}
	write_string("Mouse: Read Timeout\n");
	return 0;
}

s32int mouse_send_command(u8int command)
{
	u8int response = 0;	

	if(!mouse_wait_write())
		return 0;
	outportb(0x64, 0xD4);

	if(!mouse_wait_write())
		return 0;
	outportb(0x60, command);

	if(!mouse_wait_read())
		return 0;
	response = inportb(0x60);

	switch(response)
	{
		case 0xFA:
			//the ACK byte
			return 1;
			break;
		case 0xAA:
			//successful reset
			return 1;
			break;
		default:
			return 0;//anything else is error
			break;	
	}
}

s32int mouse_get_data(u8int* data)
{
	if(!mouse_wait_read())
		return 0;
	*data = inportb(0x60);

	return 1;
}

void mouse_handler(struct regs *r)
{
	if(!r)//something has gone very wrong...
		return;
	
	//write_string("<mouses32int>");

	mouse_get_data(&mouse_packet[mouse_packet_index]);//get the data
	mouse_packet_index++;

	if(mouse_packet_index >= 3)
	{
		//extract the packet data
		/*if(mouse_packet[0] & 10)
			pos_x -= (mouse_packet[1] / 100);//data is negative
		else
			pos_x += (mouse_packet[1] / 100);

		if(mouse_packet[0] & 20)
			pos_y -= (mouse_packet[2] / 100);//data is negative
		else
			pos_y += (mouse_packet[2] / 100);
*/
		pos_x += mouse_packet[1] / 8;
		pos_y -= mouse_packet[2] / 8;
	
		if(pos_x > 88)
			pos_x = 88;

		if(pos_y > 49)
			pos_y = 49;

		u32int oldx = get_cursor_x();
		u32int oldy = get_cursor_y();

		//set_cursor(30,49);
		set_cursor(pos_x,pos_y);
		write_char('+');
		//write_number(pos_x);
		//write_char(' ');
		//write_number(pos_y);

		set_cursor(oldx,oldy);

		//clear the packet
		memset(mouse_packet, 0, 3);
		mouse_packet_index = 0;
	}
}

void init_mouse(void)
{
#ifdef FLUIDIUM_DEBUG
	write_string("Mouse: Init\n");
#endif
	u8int status = 0;	

	//write_hex(mouse_send_command(MOUSE_RESET));

	//enable the auxilliary port
	outportb(0x64, 0xA8);
	write_hex((u32int)mouse_wait_write());

	//enable packets
	write_hex((u32int)mouse_send_command(MOUSE_AUTO_PACKETS));

	//enable the mouses32interrupt
	outportb(0x64, 0x20);//command "compaq status byte"
	status = inportb(0x60);
	status |= 0x02; //enable irq 12
	status = (u8int)(status | 0xDF); //disable mouse clock
	outportb(0x64, 0x60);//"Set compaq status"
	outportb(0x60, status);

	//install that mouse irq handler
	irq_install_handler(12, mouse_handler);

	//reset the mouse
	//write_hex(mouse_send_command(MOUSE_RESET));
	
	//TODO: negotiate the highest mouse ID possible

	

	
}
